package cn.lg.soar.common.util;

import cn.lg.soar.common.util.reflect.GenericTypeUtils;

import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 属性复制工具，是对 BeanCopier 的进一步封装，复杂复制处理请直接使用 BeanCopier
 * @author luguoxiang
 * @date 2023/01/05
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
 */
public interface PojoUtil {

    /**
     * 单个拷贝，通过实例拷贝（性能推荐）
     * @param source 源数据 源数据
     * @param target 目标数据
     * @param <S> 源数据
     * @param <T> 目标数据
     */
    static <S, T>void copy(S source, T target) {
        if (source == null || target == null) {
            return;
        }
        BeanCopier.createCacheable((Class<S>)source.getClass(), (Class<T>)target.getClass())
                .copy(source, target);
    }
    /**
     * 单个拷贝，通过实例拷贝（性能推荐）
     * @param source 源数据 源数据
     * @param target 目标数据
     * @param ignoreFields 要忽略的字段“,”隔开，（忽略的字段不会复制）
     * @param <S> 源数据
     * @param <T> 目标数据
     */
    static <S, T>void copy(S source, T target, String ignoreFields) {
        if (source == null || target == null) {
            return;
        }
        BeanCopier.createCacheable((Class<S>)source.getClass(), (Class<T>)target.getClass(), ignoreFields)
                .copy(source, target);
    }
    /**
     * 单个拷贝，通过类型
     * @param source 源数据
     * @param targetClass 目标数据类类型
     * @return
     * @param <S> 源数据
     * @param <T> 目标数据
     */
    static <S, T>T copy(S source, Class<T> targetClass) {
        if (source == null) {
            return null;
        }
        return BeanCopier.createCacheable((Class<S>)source.getClass(), targetClass)
                .convert(source);
    }
    /**
     * 单个拷贝，通过类型反射实例
     * @param source 源数据
     * @param targetClass 目标数据类类型
     * @param ignoreFields 要忽略的字段“,”隔开，（忽略的字段不会复制）
     * @return
     * @param <S> 源数据
     * @param <T> 目标数据
     */
    static <S, T>T copy(S source, Class<T> targetClass, String ignoreFields) {
        if (source == null) {
            return null;
        }
        return BeanCopier.createCacheable((Class<S>)source.getClass(), targetClass, ignoreFields)
                .convert(source);
    }

    /**
     * 批量拷贝
     * @param source 源数据
     * @param targetClass 目标数据类类型
     * @return
     * @param <S>
     * @param <T>
     */
    static <S, T> Stream<T> copyBatch(Collection<S> source, Class<T> targetClass) {
        if (source.isEmpty()) {
            return Stream.empty();
        }
        BeanCopier<S, T> beanCopier = BeanCopier.createCacheable(
                GenericTypeUtils.getElementClass(source),
                targetClass
        );
        return beanCopier.convertBatch(source);
    }
    /**
     * 批量拷贝
     * @param source 源数据
     * @param targetClass 目标数据类类型
     * @return
     * @param <S>
     * @param <T>
     */
    static <S, T> Stream<T> copyBatch(S[] source, Class<T> targetClass) {
        BeanCopier<S, T> beanCopier = BeanCopier.createCacheable(
                GenericTypeUtils.getElementClass(source),
                targetClass
        );
        return beanCopier.convertBatch(source);
    }
    /**
     * 批量拷贝
     * @param source 源数据
     * @param targetClass 目标数据类类型
     * @param ignoreFields 要忽略的字段“,”隔开，（忽略的字段不会复制）
     * @return
     * @param <S>
     * @param <T>
     */
    static <S, T> Stream<T> copyBatch(Collection<S> source, Class<T> targetClass, String ignoreFields) {
        if (source.isEmpty()) {
            return Stream.empty();
        }
        BeanCopier<S, T> beanCopier = BeanCopier.createCacheable(
                GenericTypeUtils.getElementClass(source),
                targetClass,
                ignoreFields
        );
        return beanCopier.convertBatch(source);
    }
    /**
     * 批量拷贝
     * @param source 源数据
     * @param targetClass 目标数据类类型
     * @param ignoreFields 要忽略的字段“,”隔开，（忽略的字段不会复制）
     * @return
     * @param <S>
     * @param <T>
     */
    static <S, T> Stream<T> copyBatch(S[] source, Class<T> targetClass, String ignoreFields) {
        BeanCopier<S, T> beanCopier = BeanCopier.createCacheable(
                GenericTypeUtils.getElementClass(source),
                targetClass,
                ignoreFields
        );
        return beanCopier.convertBatch(source);
    }
    /**
     * 批量拷贝
     * @param source 源数据
     * @param targetClass 目标数据类类型
     * @param handler 后置处理器
     * @return
     * @param <S>
     * @param <T>
     */
    static <S, T> Stream<T> copyBatch(Collection<S> source, Class<T> targetClass, BiFunction<S, T, T> handler) {
        if (source.isEmpty()) {
            return Stream.empty();
        }
        BeanCopier<S, T> beanCopier = BeanCopier.createCacheable(
                GenericTypeUtils.getElementClass(source),
                targetClass
        );
        return beanCopier.convertBatch(source, handler);
    }
    /**
     * 批量拷贝
     * @param source 源数据
     * @param targetClass 目标数据类类型
     * @param handler 后置处理器
     * @return
     * @param <S>
     * @param <T>
     */
    static <S, T> Stream<T> copyBatch(S[] source, Class<T> targetClass, BiFunction<S, T, T> handler) {
        BeanCopier<S, T> beanCopier = BeanCopier.createCacheable(
                GenericTypeUtils.getElementClass(source),
                targetClass
        );
        return beanCopier.convertBatch(source, handler);
    }
    /**
     * 批量拷贝
     * @param source 源数据
     * @param targetClass 目标数据类类型
     * @param ignoreFields 要忽略的字段“,”隔开，（忽略的字段不会复制）
     * @param handler 后置处理器
     * @return
     * @param <S>
     * @param <T>
     */
    static <S, T> Stream<T> copyBatch(Collection<S> source, Class<T> targetClass, String ignoreFields, BiFunction<S, T, T> handler) {
        if (source.isEmpty()) {
            return Stream.empty();
        }
        BeanCopier<S, T> beanCopier = BeanCopier.createCacheable(
                GenericTypeUtils.getElementClass(source),
                targetClass,
                ignoreFields
        );
        return beanCopier.convertBatch(source, handler);
    }
    /**
     * 批量拷贝
     * @param source 源数据
     * @param targetClass 目标数据类类型
     * @param ignoreFields 要忽略的字段“,”隔开，（忽略的字段不会复制）
     * @param handler 后置处理器
     * @return
     * @param <S>
     * @param <T>
     */
    static <S, T> Stream<T> copyBatch(S[] source, Class<T> targetClass, String ignoreFields, BiFunction<S, T, T> handler) {
        BeanCopier<S, T> beanCopier = BeanCopier.createCacheable(
                GenericTypeUtils.getElementClass(source),
                targetClass,
                ignoreFields
        );
        return beanCopier.convertBatch(source, handler);
    }

    /**
     * 批量拷贝转List
     * @param source 源数据
     * @param targetClass 目标数据类类型
     * @return
     * @param <S> 源数据
     * @param <T> 目标数据
     */
    static <S, T>List<T> copyToList(Collection<S> source, Class<T> targetClass) {
        return copyBatch(source, targetClass)
                .collect(Collectors.toList());
    }
    /**
     * 批量拷贝转List
     * @param source 源数据
     * @param targetClass 目标数据类类型
     * @param ignoreFields 要忽略的字段“,”隔开，（忽略的字段不会复制）
     * @return
     * @param <S> 源数据
     * @param <T> 目标数据
     */
    static <S, T>List<T> copyToList(Collection<S> source, Class<T> targetClass, String ignoreFields) {
        return copyBatch(source, targetClass, ignoreFields)
                .collect(Collectors.toList());
    }
    /**
     * 批量拷贝转List
     * @param source 源数据
     * @param targetClass 目标数据类类型
     * @param handler 后置处理器
     * @return
     * @param <S> 源数据
     * @param <T> 目标数据
     */
    static <S, T>List<T> copyToList(Collection<S> source, Class<T> targetClass, BiFunction<S, T, T> handler) {
        return copyBatch(source, targetClass, handler)
                .collect(Collectors.toList());
    }
    /**
     * 批量拷贝转List
     * @param source 源数据
     * @param targetClass 目标数据类类型
     * @param ignoreFields 要忽略的字段“,”隔开，（忽略的字段不会复制）
     * @param handler 后置处理器
     * @return
     * @param <S> 源数据
     * @param <T> 目标数据
     */
    static <S, T>List<T> copyToList(Collection<S> source, Class<T> targetClass, String ignoreFields, BiFunction<S, T, T> handler) {
        return copyBatch(source, targetClass, ignoreFields, handler)
                .collect(Collectors.toList());
    }

    /**
     * 批量拷贝转Set
     * @param source 源数据
     * @param targetClass 目标数据类类型
     * @return
     * @param <S> 源数据
     * @param <T> 目标数据
     */
    static <S, T>Set<T> copyToSet(Collection<S> source, Class<T> targetClass) {
        return copyBatch(source, targetClass)
                .collect(Collectors.toSet());
    }
    /**
     * 批量拷贝转Set
     * @param source 源数据
     * @param targetClass 目标数据类类型
     * @param ignoreFields 要忽略的字段“,”隔开，（忽略的字段不会复制）
     * @return
     * @param <S> 源数据
     * @param <T> 目标数据
     */
    static <S, T>Set<T> copyToSet(Collection<S> source, Class<T> targetClass, String ignoreFields) {
        return copyBatch(source, targetClass, ignoreFields)
                .collect(Collectors.toSet());
    }
    /**
     * 批量拷贝转Set
     * @param source 源数据
     * @param targetClass 目标数据类类型
     * @param handler 后置处理器
     * @return
     * @param <S> 源数据
     * @param <T> 目标数据
     */
    static <S, T>Set<T> copyToSet(Collection<S> source, Class<T> targetClass, BiFunction<S, T, T> handler) {
        return copyBatch(source, targetClass, handler)
                .collect(Collectors.toSet());
    }
    /**
     * 批量拷贝转Set
     * @param source 源数据
     * @param targetClass 目标数据类类型
     * @param ignoreFields 要忽略的字段“,”隔开，（忽略的字段不会复制）
     * @param handler 后置处理器
     * @return
     * @param <S> 源数据
     * @param <T> 目标数据
     */
    static <S, T>Set<T> copyToSet(Collection<S> source, Class<T> targetClass, String ignoreFields, BiFunction<S, T, T> handler) {
        return copyBatch(source, targetClass, ignoreFields, handler)
                .collect(Collectors.toSet());
    }

}
